/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 * 类构造函数名为 init(),在init()定义指定的参数，可在实例化类时指定参数传入到init()
 */
// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
 
  // The base Class implementation (does nothing)
  this.Class = function(){};
 
  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;
   
    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;
   
    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;
           
            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];
           
            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);        
            this._super = tmp;
           
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
   
    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
   
    // Populate our constructed prototype object
    Class.prototype = prototype;
   
    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;
 
    // And make this class extendable
    Class.extend = arguments.callee;
   
    return Class;
  };
})();

var Event = Class.extend({
    init : function() {
        this.pools   = [];
        this.eventer = {};
    },

    on : function(ev, fn) {
        this.pools.push({ev : ev, fn : fn});
        $(this.eventer).on(ev, fn);
    },

    off : function(ev) {
        if (typeof(ev) == 'undefined' || ev === null) {
            this.pools = [];
            $(this.eventer).off();

            return true;
        }

        $(this.eventer).off(ev);
        var _this = this;

        $.each(this.pools, function(k, v) {
            if (typeof(v) == 'undefined') {
                return ;
            }

            if (v.ev == ev) {
                delete _this.pools[k];
            }
        })
    },

    trigger : function(ev, param) {
        $(this.eventer).trigger(ev, param);
    }
});

/**  Model
 * 模型类
 */
var Model = Event.extend({
    init : function(dao) {
        this._super();

        this.dao = dao || {};

        this.set(this.dao);
    },

    /**
     * 可以指定键名，值的形式
     * 也可以直接指定一个json形式，一次性set多个值
     *
     * set('a', 'val')
     * set({a : 'val' , b : 'val2'})
     */
    set : function(k, v) {
        var dao = {};

        if (typeof(k) == 'object' && k !== null) {
            dao = k;
        } else {
            dao[k] = v;
        }

        /**
         * p prev  表示之前的值
         * n new   表示新值
         */
        var _this = this,
            p, n;

        /**
         * 先设置所有值，然后再逐一触发事件
         * 否则可能会出现监听的事件被触发，但是后续还未设置的值获取不到
         */
        $.each(dao, function(k, v) {
            p = _this.dao[k] || null;
            n = v;

            _this.dao[k] = v;
        })

        $.each(dao, function(k, v) {
            /**
             * 目前只支持 属性名:set事件，触发事件时传递新值和前一次的值
             * 如需其它事件触发，可使用Model.trigger()
             */
            _this.trigger(k + ':set', [n, p]);   //
        })
    },

    /**
     * 如果不指定k，则返回所有数据
     */
    get : function(k) {
        if (typeof(k) == 'undefined') {
            return this.dao;
        }

        return this.dao[k] || null;
    }

});

/**
 *  组合模式基类
 */
var Component = Class.extend({
    init : function() {
        this.childs = [];
    },

    addChild : function(o) {
        this.childs.push(o);
    },

    getChilds : function() {
        return this.childs;
    },

    /**
     * 清空this.childs
     */
    cleanChilds : function() {
        this.childs = [];
    },

    run : function(cmd) {
        $.each(this.getChilds(), function(k, v) {
            if (typeof(v[cmd]) != 'undefined') {
                v[cmd]();
            }
        })
    }
});

/**
 * 参数配置类 
 */
var Conf = {};

Conf.set = function(k, v) {
    if(typeof(k) == 'object') {
        for(var p in k) {
            Conf[p] = k[p];
        }
    } else {
        Conf[k] = v;
    }
}

Conf.get = function(k) {
    return Conf[k];
}

/**
 * 表单保单、回填数据
 *
 */
var Form = Event.extend({
    init : function($form, model, opts) {
        this._super();

        this.$form = $form;
        this.model = model || null;
        this.opts  = {
            showSuccessMsg : 0,    //是否显示操作成功的提示信息，1显示，0不显示
            finish         : null, //执行完成返回结果后的回调函数，传递到回调函数的值为执行返回的结果

            /**
             * 是否以ajax方式提交数据,如果不以ajax提交数据则直接使用form的行为
             * isAjax : 0时, showSuccessMsg、finish属性无效
             */
            isAjax : 1,
            method : 'post'    //表单提交方式
        };

        if (typeof(opts) == 'object' && opts !== null) {
            this.setOpts(opts);
        }

        this.initEvent();
        this.fill();
    }, 

    setOpts : function(k, v) {
        var dao   = (typeof(k) == 'object' && k !== null) ? k : {k : v},
            _this = this;

        $.each(dao, function(_k, _v) {
            if (typeof(_v) != 'undefined') {
                _this.opts[_k] = _v;

                if (_k == 'finish') {
                    _this.setFinish();  //激活finish事件
                }
            }
        })

        return true;
    },

    setFinish : function(fn) {
        if (typeof(fn) == 'function') {
            this.opts.finish = fn;
        }

        if (typeof(this.opts.finish) != 'function') {
            return false;
        }

        var _this = this;

        this.on('Form.finish', function(e, j) {
            _this.opts.finish.call(_this, e, j);
        })
    },

    initEvent : function() {
        var _this = this;

        var saveAction = function(e) {
            e.preventDefault();
            _this.save.call(_this);
        }

        this.$form.find('[type=submit]').click(saveAction);

        this.$form.find('[type=reset]').click(function() {
            _this.reset.call(_this);
        })

        this.setFinish();

        /**
         * 将与表单关联的所有 保存 按钮增加绑定事件
         * 表单关联保存按钮命名规则： 表单id-save-btn
         */
        if (this.$form.attr('id')) {
            var allSaveBtnKey = this.$form.attr('id') + '-save-btn',    //关联的保存按钮
                $allSaveBtn = $('[t=' + allSaveBtnKey + ']');

            $allSaveBtn.click(saveAction);
        }
    },

    setModel : function(model) {
        this.model = model;
    },

    /**
     * 复位表单，清空span[name]节点的值
     */
    reset : function() {
        this.$form[0].reset();
        this.fillSpan();
    },

    /**
     * 将dao中键名与span[name]属性相同的数据填充至span[name]中
     */
    fillSpan : function(model){
        m = model || this.model;

        this.$form.find('span[name]').each(function(){
            var name  = $(this).attr('name');

            $(this).html(m.get(name));
        });
    },

    /**
     * 填充数据至表单和文本节点
     * input:checkbox的选中值用数组的形式表述
     */
    fill : function(model) {
        m = model || this.model;

        if (m === null) {
            return true;
        }

        this.fillSpan(m);

        var _this = this;

        $.each(m.get(), function(k, v){
            if(typeof(v) == 'function') {
                return ;
            }

            var name = typeof(v) == 'object' && v != null ? k + '\\[\\]' : k,
                $o = _this.$form.find('[name='+ name + ']'),
                type = $o.length  ? $o[0].type : undefined,
                check = {checked : true};

            if(typeof(type) == 'undefined') {
                return;
            }

            switch(type) {
                case 'radio' :
                    $o.filter('[value=' + v + ']').attr(check);
                    break;

                case 'checkbox' :
                    if(typeof(v) == 'object') {
                        $.each(v, function(k2, v2){
                            if (v2) {
                                $o.filter('[value=' + v2 + ']').attr(check);
                            }
                        });
                    } else {
                        $o.filter('[value=' + v + ']').attr(check);
                    }
                    break;

                default : 
                    $o.val(v);
            }
        });
    },

    /**
     * 返回表单中数据，结果为json格式
     */
    getDao : function() {
        var dao = this.$form.serializeArray(),
            r = {};

        $.each(dao, function(k, v){
            if(typeof(v.value) != 'undefined') {
                var index = v.name.indexOf('['); //名字中包含有[表示数组 

                if(index != -1) {
                    var tmpName = v.name.substr(0, index);

                    if(typeof(r[tmpName]) == 'undefined') {
                        r[tmpName] = [];
                    }

                    r[tmpName].push(v.value);
                } else {
                    r[v.name] = v.value;
                }
            }
        });

        return r;
    },

    save : function() {
        var $form = this.$form,
            url   = $form.attr('action'),

            /**
             * <form>标签中增加go属性，此属性值可以网址、１、０，如果是网址则跳转到指定网址，1表示刷新当前页，0表示不刷新
             * 默认为1，提交后返回成功状态自动刷新当前页面
             */
            go    = $form.attr('go') || '1',
            d     = this.getDao(),
            _this = this,
            method = $form.attr('method') || this.opts.method;

        if (!this.opts.isAjax) {
            if (method.toUpperCase() == 'GET') {
                var _d = $form.serialize();
                url = url + ((url.indexOf('?') != -1) ? '&' : '?') + _d;
                window.location.href = url;
            } else {
                $form[0].submit();
            }

            return true;
        }

        $[method](url, d, function(j) {
            if (!j.s) {
				alert(j.m);
                return false;
            }

            var goVal = typeof(j.go) == 'undefined' ? go : j.go,
                goUrl;

            switch (goVal) {
                case '0' :
                    goUrl = '';
                    break;

                case '1' :
                    goUrl = window.location.href;
                    break;

                default :
                    goUrl = goVal;
            }

            if (typeof(_this.opts.finish) == 'function') {
                j.go = goUrl;

                _this.trigger('Form.finish', [j]);

                return true;
            }

            if (goUrl) {
                if (_this.opts.showSuccessMsg) {
                    $(_this.eventer).on('Form-save-finish-dialog-close', function() {
                        redirect(goUrl);
                    })
                } else {
                    redirect(goUrl);

                    return true;
                }
            }

            if (j.msg && _this.opts.showSuccessMsg) {
                var d = dialog({
                    title       : '提示',
                    content     : j.msg,
                    fixed       : true,
                    cancelValue : '关闭',
                    width       : 300,
                    cancel      : function() {
                        $(_this.eventer).trigger('Form-save-finish-dialog-close');
                    }
                })

                d.showModal();
            }
        }, 'json');
    }
});


/**
 * 数据删除等需要警告提示信息的地方都可以调用此函数
 * 调用方法是在相应html标签上加入以下全部或部分属性，其中有星号的为必选属性
 * *t="firm"   此为firm调用标记
 * *m="操作警告信息”
 * *href="接收操作的网址“
 * ct="多选项对应的html标签t属性的值"   通过html标签中的t属性确定有哪些checkbox是需要被操作的  ct = checkbox tag
 * nc="有多选项目需要操作时，但没有选中项目时的提示信息"   //ncm = not checked
 * go="执行完成后跳转的地址”   值为：1表示刷新当前页面; -1表示不执行任何操作; 如果是网址就跳转到此网址。默认值为1
 *
 * 如果未指定cg，那么忽略nc、cn属性
 * 如果href执行完成后返回的结果中有go参数，那么忽略firm go属性值，采用此处的go值
 *
 * href对应网址传过来可识别的参数：
 *  status 表示执行状态  true/false
 *  msg 提示信息
 *  go  表示跳转到的地址
 *
 * @return void
 */
var firm_2 = function() {
    var tag = 'firm';   //firm操作的识别符

    /**
     * 初始化
     */
    var init = function() {
        $('[t=' + tag + ']').click(function(e){
            e.preventDefault(); //阻止html标签默认行为，主要是阻止a跳转

            var msg   = $(this).attr('m') || '确认执行操作吗',
                url   = $(this).attr('href'),
                goUrl = $(this).attr('go') || '1',
                checkboxTag   = $(this).attr('ct'),
                notCheckedMsg = $(this).attr('nc') || '请选择需要操作的项目',
                dao = checkboxTag ? getCheckboxVals(checkboxTag) : null;

            if (!url) {
                alert('请指定执行操作的地址');

                return false;
            }

            if (goUrl == '1') {
                goUrl = window.location.href;
            } else if(goUrl.length > 2) {
            } else {
                goUrl = '';
            }

            if (checkboxTag && (!dao || dao === null)) {
                alert(notCheckedMsg);

                return false;
            }

            if (!confirm(msg)) {
                return false;
            }

            run(url, dao, goUrl);
        })
    };

    var getCheckboxVals = function(checkboxTag) {
        if (!checkboxTag) {
            return false;
        }

        var $o = $('[g=' + checkboxTag + ']:checked');

        if($o.length < 1) {
            return false;
        }

        var key = '',
            vals = [];

        /**
         * 获取被选中的值
         */
        $o.each(function(k, v) {
            $_o = $(v);

            if (!key) {
                key = ($_o.attr('name')).replace(/\[\]/g, '');
            }

            vals.push($_o.val());
        });

        if (vals.length < 1) {
            return false;
        }

        var r;

        return (r[key] = vals);
    };

    /**
     * 执行操作
     */
    var run = function(url, dao, go) {
        var action = dao && dao === null ? 'get' : 'post';

        $[action](url, dao, function(j) {
            if (!j.status) {
                alert(j.msg);
				
                return false;
            }

            go = j.go || go;

            if (go) {
                redirect(go);
            }

            return true;
        }, 'json');
    };
    

    init();
};


/**
 * redirect
 * 跳转到指定网址
 *
 * @param url $url
 * @access public
 * @return void
 */
function redirect(url) {
    window.location.href = url;

    return;

    /*
    var rand = '__redirect_rand=' + (Math.random());

    url += url.indexOf('?') === -1 ? '?' : '&';
    url += rand;

    window.location.href = url;
    */
}

/**
*  加法
*/
function floatAdd(arg1,arg2) {
  var r1,r2,m;
  try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}
  try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}
  m=Math.pow(10,Math.max(r1,r2))
  return (arg1*m+arg2*m)/m
}
/**
*  减法
*/
function floatSub(arg1,arg2) {
  var r1,r2,m,n;
  try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}
  try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}
  m=Math.pow(10,Math.max(r1,r2));
  //动态控制精度长度
  n=(r1>=r2)?r1:r2;
  return ((arg1*m-arg2*m)/m).toFixed(n);
}
/**
*  乘法
*/
function floatMul(arg1,arg2) {
  var m=0,s1=arg1.toString(),s2=arg2.toString();
  try{m+=s1.split(".")[1].length}catch(e){}
  try{m+=s2.split(".")[1].length}catch(e){}
  return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
}
/**
*  除法
*/
function floatDiv(arg1,arg2) {
  var t1=0,t2=0,r1,r2;
  try{t1=arg1.toString().split(".")[1].length}catch(e){}
  try{t2=arg2.toString().split(".")[1].length}catch(e){}
  with(Math){
    r1=Number(arg1.toString().replace(".",""))
    r2=Number(arg2.toString().replace(".",""))
    return (r1/r2)*pow(10,t2-t1);
  }
}


/**
 * 控制多选项选中或取消
 * 控制选中的选项框加上t属性，其值以 -chk-act-a 结尾
 * 被选项t属性值以 -chk-act-c 结属
 */
var chkAct = function() {
    var tag = '-chk-act-',
        a   = tag + 'a',
        c   = tag + 'c';

    $('[t$=' + a + ']:checkbox').click(function() {
        var child = ($(this).attr('t')).replace(new RegExp(a), c),
            s     = $(this).attr('checked') ? true : false;

        $('[t=' + child + ']:checkbox').attr('checked', s);
    })
};
